define([], function () {  
	'use strict';
	var PDFMatrix = function() {
		this.a = 1;//float
		this.b = 0; //float
		this.c = 0; //float
		this.d = 1; //float
		this.e = 0; //float
		this.f = 0; //float

		this.Set = function (a, b, c, d, e, f) {
			this.a = a;
			this.b = b;
			this.c = c;
			this.d = d;
			this.e = e;
			this.f = f;
		};

		this.Reset = function () {
			this.a = this.d = 1;
			this.b = this.c = this.e = this.f = 0;
		};

		this.SetReverse = function (mt) {
			var i = mt.a * mt.d - mt.b * mt.c;
			if (i  == 0) return;
			var j = -i;
			this.a = mt.d / i;
			this.b = mt.b / j;
			this.c = mt.c / j;
			this.d = mt.a / i;
			this.e = (mt.c * mt.f - mt.d * mt.e) / i;
			this.f = (mt.a * mt.f - mt.b * mt.e) / j;
		};

		//fRadian Ϊ���ȣ�2*Math.PI/360 * o������ǽǶȣ�
		this.Rotate = function (fRadian, bPrepended) {
			var cosValue = Math.cos(fRadian);
			var sinValue = Math.sin(fRadian);
			var m = new WebPDF.PDFMatrix();
			m.Set(cosValue, sinValue, -sinValue, cosValue, 0, 0);
			var rel = null;
			if (bPrepended)
				rel = WebPDF.PDFMatrix.Concat2mt(m, this);
			else
				rel = WebPDF.PDFMatrix.Concat2mt(this, m);
			this.Set(rel.a, rel.b, rel.c, rel.d, rel.e, rel.f);

		};
		this.RotateAt = function (dx, dy, fRadian, bPrepended) {
			this.Translate(dx, dy, bPrepended);
			this.Rotate(fRadian, bPrepended);
			this.Translate(-dx, -dy, bPrepended);
		};
		this.Concat = function (a, b, c, d, e, f, bPrepended) {
			var m = new WebPDF.PDFMatrix();
			m.Set(a, b,c,d,e,f); 
			var rel = null;   
			 if(bPrePended){
				rel = WebPDF.PDFMatrix.Concat2mt(m, this);
			 }
			 else{
			 rel = WebPDF.PDFMatrix.Concat2mt(this, m);
			 }
			 this.Set(rel.a, rel.b, rel.c, rel.d, rel.e, rel.f);

		};
		//is 90 degree or -90 degree rotated
		this.Is90Rotated = function () {
			var a1 = this.a * 1000;
			if (a1 < 0) a1 *= -1;
			var d1 = this.d * 1000;
			if (d1 < 0) d1 *= -1;
			var b1 = this.b;
			if (b1 < 0) b1 *= -1;
			var c1 = this.c;
			if (c1 < 0) c1 *= -1;
			return (a1 < b1) && (d1 < c1);

		};

		this.IsScaled = function () {
			var b1 = this.b * 1000;
			if (b1 < 0) b1 *= -1;
			var c1 = this.c * 1000;
			if (c1 < 0) c1 *= -1;
			var a1 = this.a;
			if (a1 < 0) a1 *= -1;
			var d1 = this.d;
			if (d1 < 0) d1 *= -1;
			return (b1 < a1) && (c1 < d1);
		};

		this.GetA = function () { return this.a; };
		this.GetB = function () { return this.b; };
		this.GetC = function () { return this.c; };
		this.GetD = function () { return this.d; };
		this.GetE = function () { return this.e; };
		this.GetF = function () { return this.f; };

		this.Translate = function (x, y, bPrepended) { 
			if(bPrepended) {
				thi.e += x * this.a + y * this.c;
				this.f += y * this.d + x * this.b;
			}
			else
				this.e += x, this.f += y;

		};

		this.Scale = function (sx, sy, bPrepended) {
			this.a *= sx, this.d *= sy;
			if (bPrepended) {
				this.b *= sx;
				this.c *= sy;
			}
			else {
				this.b *= sy;
				this.c *= sx;
				this.e *= sx;
				this.f *= sy;
			}
		};
		this.TransformXDistance = function (dx) {
			var fx = this.a * dx;
			var fy = this.b * dx;
			return Math.sqrt(fx * fx + fy * fy);
		};

		this.TransformYDistance = function (dy) {
			var fx = this.c * dy;
			var fy = this.d * dy;
			return Math.sqrt(fx * fx + fy * fy);
		};

		this.TransformDistance = function (dx, dy) {
			var fx = this.a * dx + this.c * dy;
			var fy = this.b * dx + this.d * dy;
			return Math.sqrt(fx * fx + fy * fy);
		};
		this.TransFormPoint = function (x, y) {
			var fx = this.a * x + this.c * y + this.e;
			var fy = this.b * x + this.d * y + this.f;
			var rel = [];
			rel[0] = parseFloat(fx.toFixed(3)); rel[1] = parseFloat(fy.toFixed(3));
			return rel;
		};
		this.TransFormRect = function (left, top, right, bottom) {
			var transform = function (l, r, t, b) {
				var x = [], y = [];
				x[0] = l; y[0] = t;
				x[1] = l; y[1] = b;
				x[2] = r; y[2] = t;
				x[3] = r; y[3] = b;
				var point;
				for (var i = 0; i < 4; i++) {
					point = this.TransFormPoint(x[i], y[i]);
					x[i] = point[0]; y[i] = point[1];
				}
				point = null;
				// rel[0]: left  rel[1]: right
				// rel[2]: top   rel[3]: bottom
				var rel = [x[0], x[0], y[0], y[0]];
				for (i = 1; i < 4; i++) {
					if (rel[0] > x[i]) rel[0] = x[i];
					if (rel[1] < x[i]) rel[1] = x[i];
					if (rel[2] > y[i]) rel[2] = y[i];
					if (rel[3] < y[i]) rel[3] = y[i];
				}
				return rel;
			};

			var temp = transform.call(this, left, right, top, bottom);
			var rst = [];
			rst[0] = temp[0]; rst[1] = temp[2];
			rst[2] = temp[1]; rst[3] = temp[3];
			temp = null;
			transform = null;

			// rst[0]: left    rst[1]: top
			// rst[2]: right   rst[3]: bottom
			return rst;
		};
		this.GetXUnit = function () {
			if (b===0) {
				return Math.abs(a);
			}
			else if (a===0) {
				return Math.abs(b);
			}
			else {
				return Math.sqrt(a*a+b*b);
			}
		};
		this.GetYUnit = function () {
			if (c===0) {
				return Math.abs(d);
			}
			else if (d===0) {
				return Math.abs(c);
			}
			else {
				return Math.sqrt(c*c+d*d);
			}
		};
		this.GetUnitRect = function () {
			return this.TransFormRect(0, 0, 1, 1);
		};
		this.MatchRect = function (dest, src) {
			var fDiff = src[0] - src[2];
			this.a = Math.abs(fDiff) < 0.001 ? 1 : (dest[0] - dest[2]) / fDiff;
			fDiff = src[3] - src[1];
			this.d = Math.abs(fDiff) < 0.001 ? 1 : (dest[3] - dest[1]) / fDiff;
			this.e = dest[0] - src[0] * this.a;
			this.f = dest[3] - src[3] * this.d;

			this.b = 0;
			this.c = 0;
		};		
	};

	PDFMatrix.Concat2mt = function(m1, m2){
			var aa = m1.a * m2.a + m1.b * m2.c;
			var bb = m1.a * m2.b + m1.b * m2.d;
			var cc = m1.c * m2.a + m1.d * m2.c;
			var dd = m1.c * m2.b + m1.d * m2.d;
			var ee = m1.e * m2.a + m1.f * m2.c + m2.e;
			var ff = m1.e * m2.b + m1.f * m2.d + m2.f;
			var m = new WebPDF.PDFMatrix();
			m.Set(aa, bb, cc, dd, ee, ff);
			return m;
	};

    return PDFMatrix;
});